//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#ifndef __GRAFIX_WINDOW_STACK_H__
#define __GRAFIX_WINDOW_STACK_H__

#include <engine.h>

#define TIME_PRECISE        50              // window timer precision
#define KEY_CACHE           8

#define MaxNumAnime        64

struct KBDData {
    Byte scanCode;
    Byte virKey;
    Int16 flags;
    Int32 keyPress;
    Int16 ledStatus;
    Int16 kbdStatus;
    Byte keyboardIdentifier;
};

struct KPDData {
    Int32 keycode;
    Int32 status;
};

struct MouseData {
    UInt8 status;
    UInt8 x;
    UInt8 y;
    UInt8 reserve;
};

struct TouchData {
    struct{
        UInt16 dir:8;
        UInt16 index:4;
        UInt16 fingers:4;
    };

    Int16 x;
    Int16 y;
};

class CGrafixObject;

typedef struct {
    Int32 keyValue;
    InputMask modifier;
    CGrafixObject* grabber;
} GrabbedKey;

typedef struct {
    Int32 keyValue;
    InputMask modifier;
    CGrafixObject* intercepter;
} InterceptedKey;

class BufferCacheNode;

class AnimationLayer : public DLinkNode {
public:
    AnimationLayer() {
        Initialize();
        effect = TransitionEffect_None;
    }

    BufferCacheNode* buffer;
    TransitionEffect effect;
    Int32 x, y, width, height, opacity;
    Boolean alive;

    Int32 leadingOffsetX, leadingOffsetY, leadingOpacity, leadingSpeed;
    Int32 trailingOffsetX, trailingOffsetY, trailingOpacity, trailingSpeed;
};

class CGrafixEngine;
class CGrafixSurface;
class CGrafixEventBuffer;

//
// GrafixObjectStack manager the window, and doesn't hold the window's reference
//

class GrafixObjectStack
{
public:
    Void *operator new(size_t size, Void* pv) { return pv; }

    Void *operator new(size_t size) { return malloc(size); }

    Void operator delete(Void* pv) { free(pv); }

    ECode Initialize(
        /* [in] */ CGrafixEngine* engine,
        /* [in] */ Int32 width,
        /* [in] */ Int32 height);

    ~GrafixObjectStack();

public:
    ECode RenderDriver(
        /* [in] */ Region* region);

    ECode AcquireEventBuffer(
        /* [in] */ Int32 contextID,
        /* [out] */ CGrafixEventBuffer** eventbuffer);

    Void GetMainWindow(
        /* [in] */ Int32 appletID,
        /* [out] */ CGrafixObject** owner);

    ECode AddWindow(
        /* [in] */ CGrafixObject* window);

    Void RemoveWindow(
        /* [in] */ CGrafixObject* window);

    ECode CleanWindowResource(
        /* [in] */ CGrafixObject* window);

    ECode UpdateFocus();

    ECode PostButtonEvent(
        /* [in] */ GrafixObjectEvent& event);

    ECode PostKeyEvent(
        /* [in] */ GrafixObjectEvent& event);

    ECode Update(
        /* [in] */ Region* region  = NULL,
        /* [in] */ Int32 end = 0);

    ECode UpdateRegion(
        /* [in] */ Int32 start,
        /* [in] */ Int32 end,
        /* [in] */ Region* region);

    Boolean GetFlip(
        /* [in] */ Int32 end = 0);

    Void UpdateFlip(
        /* [in] */ Int32 start,
        /* [in] */ Int32 end,
        /* [in] */ Region* region);

    Void UpdateDirectVisible(
        /* [in] */ Int32 start,
        /* [in] */ Int32 end,
        /* [in] */ Region* region);

    Int32 AdjustWindowFloor(
        /* [in] */ Int32 oldIndex,
        /* [in] */ Int32 newIndex);

    Void AssurePriority(
        /* [in] */ Int32 begin);

    Void Dump();

    Void Check(
        /* [in] */ CGrafixObject* window);

    ECode Restack(
        /* [in] */ CGrafixObject* window,
        /* [in] */ Boolean up = TRUE);

    ECode DrawBackground(
        /* [in] */ Region* region);

    ECode GetPointWindow(
        /* [in] */ Boolean order,
        /* [in] */ Int32 exceptId,
        /* [out] */ CGrafixObject** window);

    ECode GetFoucusWindow(
        /* [in] */ Boolean order,
        /* [out] */ CGrafixObject** window);

    ECode SwitchFocus(
        /* [in] */ CGrafixObject* after);

    Void  GetKeyboardWindow(
        /* [in] */ GrafixObjectEvent& event,
        /* [out] */ CGrafixObject** window);

    ECode AddAnimationLayer(
        /* [in] */ CGrafixObject* window);

    Int32 AddAnimation(
        /* [in] */ cBaseAnimation* anime);

    Void RemoveAllAnimationLayer();

    Void InternalDeleteAnime(
        /* [in] */ Int32 index);

    Void InternalDeleteAllAnime();

    Void UpdateAnimation();

    Void SetOrientation (
        /* [in] */ ScreenOrientation orientation);

    Void MarkAnimationSymbol(
        /* [in] */ Int32 current,
        /* [in] */ Region* updateRegion);

    STATIC UInt32 GetWindowId()
    {
        return m_windowId++;
    }

public:
    CGrafixEngine* m_engine;

    Int32 m_width;
    Int32 m_height;

    CGrafixSurface* m_primarySurface;
    CGrafixSurface* m_backgroundSurface;

    CGrafixSurface* m_transitionSurface;

    CGrafixObject* m_cursor;  // super-toplevel-window
                        // or software cursor

public:
    FusionVector m_windows;
    STATIC UInt32 m_windowId;

    // just for sync window enumerator.
    //
    Boolean m_grafixObjectStackChanged;

    CGrafixObject* m_pointerWindow;       // grabbing the pointer
    CGrafixObject* m_enteredWindow;       // under the pointer
    CGrafixObject* m_keyboardWindow;      // grabbing the keyboard
    CGrafixObject* m_focusedWindow;       // having the focus

    FusionVector m_interceptedKeys;

    FusionVector m_grabbedKeys;     // List of grabbed keys.

    // It's for key release when the focus leave this window
    //
    struct
    {
        Int32 keyValue;
        CGrafixObject* owner;
    } m_keys[KEY_CACHE];

    FusionVector m_timeWindows;
    IEvent* m_timeEvent;
    IThread* m_timeThread;

    IThread* m_keyThread;
    IThread* m_cursorThread;

#ifdef GUI_AUTO_TEST
    IThread* m_randEvent;
#endif

    Boolean m_haveInput;

public:
    IDeviceDriver* m_cursorDriver;
    IDeviceDriver* m_keyDriver;

    Boolean m_terminate;
    Boolean m_enableInput;  // to indicate whether GrafixObjectStack can receive
                            // mouse or key events. it will be set FALSE when
                            // animation starts in order to forbid user invoking
                            // events that will be responded after animation
                            // stops.

    //
    // below variable for windows transform.
    //

    AnimationLayer m_animationHeader;

    cBaseAnimation* m_pAnime[MaxNumAnime];

    Int32   m_nNumberOfAnimes;
    Int32   m_pAvailableSlot;
    Boolean m_bActiveFlag;

    // If the animation stack changed, the variable m_layerChanged be set TRUE.
    //
    Boolean m_layerChanged;

    // wake up the animation thread.
    //
    IEvent* m_invokeAnimation;
    IThread* m_animationThread;

    ScreenOrientation m_orientation;
};

#endif  // __GRAFIX_WINDOW_STACK_H__
